﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using Cms.Data;
using Cms.Domain;
using Cms.Domain.Comparers;
using Cms.Domain.RepositoryInterfaces;
using iLib.Web.UI;
using SortDirection = Cms.Domain.SortDirection;

namespace Cms.Web.Framework.Controls
{
    public class UserGroupSelector : Control, INamingContainer
    {
        // Controls
        private IList<UserGroup> _availableGroups;
        private IList<UserGroup> _deselectedGroups;
        private bool _groupsAreSet;
        private IList<UserGroup> _inheritedGroups;
        private int _offsetLeft;
        private int _offsetTop;
        private IList<UserGroup> _selectedGroups;
        private bool _showTabOverlay;
        private Button btnSelect;
        private HtmlInputHidden hidSelectedValues;

        public UserGroupSelector()
        {
            _offsetTop = -2;
            _offsetLeft = -15;
        }

        //Properties
        public bool ShowTabOverlay
        {
            get { return _showTabOverlay; }
            set { _showTabOverlay = value; }
        }

        public int OffsetTop
        {
            get { return _offsetTop; }
            set { _offsetTop = value; }
        }

        public int OffsetLeft
        {
            get { return _offsetLeft; }
            set { _offsetLeft = value; }
        }

        public void SetGroups(IList<UserGroup> availableGroups, IList<UserGroup> inheritedGroups, IList<UserGroup> selectedGroups, IList<UserGroup> deselectedGroups)
        {
            _availableGroups = availableGroups;
            _inheritedGroups = inheritedGroups;
            _selectedGroups = selectedGroups;
            _deselectedGroups = deselectedGroups;
            _groupsAreSet = true;
        }
        
        public IEnumerable<UserGroup> GetSelectedGroups()
        {
            return _selectedGroups;
        }

        public IEnumerable<UserGroup> GetDeselectedGroups()
        {
            return _deselectedGroups;
        }
        
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            if (_groupsAreSet)
                return;
            _availableGroups = ViewState["AvailableGroups"] == null
                                   ? new List<UserGroup>()
                                   : IDsToGroups(ViewState["AvailableGroups"].ToString());
            _inheritedGroups = ViewState["InheritedGroups"] == null
                                   ? new List<UserGroup>()
                                   : IDsToGroups(ViewState["InheritedGroups"].ToString());
            _selectedGroups = ViewState["SelectedGroups"] == null
                                  ? new List<UserGroup>()
                                  : IDsToGroups(ViewState["SelectedGroups"].ToString());
            _deselectedGroups = ViewState["DeselectedGroups"] == null
                                    ? new List<UserGroup>()
                                    : IDsToGroups(ViewState["DeselectedGroups"].ToString());
        }

        protected override void CreateChildControls()
        {
            base.CreateChildControls();
            btnSelect = new Button();
            btnSelect.Click += btnSelect_Click;
            btnSelect.Text = "Select";
            btnSelect.Attributes.CssStyle.Add("position", "absolute");
            btnSelect.Attributes.CssStyle.Add("left", "-10000px");
            Controls.Add(btnSelect);
            hidSelectedValues = new HtmlInputHidden();
            Controls.Add(hidSelectedValues);
            string script = "function CollectSelectedGroups(popupID, hidID) {" +
                            "var inputs = document.getElementById(popupID).getElementsByTagName('input');" +
                            "var ids = '';" +
                            "for (var i = 0; i < inputs.length; i++) {" +
                            "if (inputs[i].checked) {" +
                            "if (ids != '') " +
                            "ids += ',';" +
                            "ids += inputs[i].value;" +
                            "}" +
                            "}" +
                            "document.getElementById(hidID).value = ids;" +
                            "}";
            ClientScriptProxy.Current.RegisterClientScriptBlock(this, Page.GetType(), "GroupSelector", script, true);
        }

        protected void btnSelect_Click(object sender, EventArgs e)
        {
            // Collect IDs from comma-separated string stored in hidden input
            IList<int> ids = new List<int>();
            foreach (string id in hidSelectedValues.Value.Split(",".ToCharArray()))
            {
                if (id != string.Empty)
                    ids.Add(int.Parse(id));
            }

            // Add groups
            IUserRepository userRepository = new UserRepository();
            foreach (int id in ids)
            {
                UserGroup group = userRepository.GetUserGroup(id);
                if (!_selectedGroups.Contains(group) && !_inheritedGroups.Contains(group))
                    _selectedGroups.Add(group);
            }

            // Remove groups
            int i = 0;
            while (i < _selectedGroups.Count)
            {
                if (ids.Contains(_selectedGroups[i].ID))
                {
                    i++;
                    continue;
                }
                _selectedGroups.RemoveAt(i);
            }

            // Add inherited, removed groups to the deselected list
            _deselectedGroups.Clear();
            foreach (UserGroup inheritedGroup in _inheritedGroups)
            {
                if (!ids.Contains(inheritedGroup.ID))
                    _deselectedGroups.Add(inheritedGroup);
            }
        }
        
        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            string selectedGroups = string.Empty;
            List<UserGroup> allSelectedGroups = _inheritedGroups.ToList();
            foreach (UserGroup deselectedGroup in _deselectedGroups)
                allSelectedGroups.Remove(deselectedGroup);
            allSelectedGroups.AddRange(_selectedGroups.Where(c => !_inheritedGroups.Contains(c)));
            allSelectedGroups.Sort(new UserGroupNameComparer(SortDirection.Ascending));
            foreach (UserGroup group in allSelectedGroups)
            {
                if (selectedGroups != string.Empty)
                    selectedGroups += ", ";
                if (_inheritedGroups.Contains(group))
                    selectedGroups += "<span class=\"inheritedCategory\">" + group.Name + "</span>";
                else
                    selectedGroups += group.Name;
            }
            if (selectedGroups == string.Empty)
                selectedGroups = "No groups selected.";
            string link = @"<a onclick=""cms.Lists.ShowPopup(document.getElementById('" + ClientID +
                          @"_popup'), this, 'left', " + _offsetLeft + ", " + _offsetTop +
                          @", true, event); iLib.Dom.PreventBubble(event);"" href=""javascript:void(0);"">Select groups</a>";
            Controls.Add(new LiteralControl(selectedGroups + "<br/>" + link));

            string popup = @"<div id=""" + ClientID +
                           @"_popup"" class=""popup"" onclick=""iLib.Dom.PreventBubble(event);""><div class=""popupMenuTop""><div class=""popupMenuTopBg"">&nbsp;</div>"
                           +
                           @"<div class=""popupMenuTopLeftCorner"">&nbsp;</div><div class=""popupMenuTopRightCorner"">&nbsp;</div>"
                           + @"</div><div class=""popupMenu""><div class=""popupMenuLeftBg"">&nbsp;</div>"
                           +
                           @"<div class=""popupMenuRightBg"">&nbsp;</div><div class=""popupMenuContentNoGutter""><div style=""margin: 8px;margin-top:4px;"">";

            foreach (UserGroup group in _availableGroups)
            {
                popup += @"<div><input type=""checkbox""";
                if ((_inheritedGroups.Contains(group) & !_deselectedGroups.Contains(group)) ||
                    _selectedGroups.Contains(group))
                    popup += " checked";

                //if (_inheritedGroups.Contains(group))
                //    popup += " disabled";
                popup += @" value=""" + group.ID + @"""/><span";
                if (_inheritedGroups.Contains(group))
                    popup += " class=\"inheritedCategory\"";
                popup += ">" + group.Name + "</span></div>";
            }
            Controls.Add(new LiteralControl(popup));

            popup =
                @"<div class=""horizontalDivider"" style=""margin-bottom: 3px; margin-top: 4px; margin-left: 0px; margin-right: 0px;""></div>" +
                @"<a href=""javascript:void(0);"" onclick=""";
            if (_showTabOverlay)
                popup += "cms.Edit.ShowTabOverlays();";
            popup += "CollectSelectedGroups('" + ClientID + "_popup', '" + hidSelectedValues.ClientID + "');" +
                     "document.getElementById('" + btnSelect.ClientID +
                     @"').click();""><img src=""Admin/Img/icons/accept.png"" /><span>Select</span></a>";
            Controls.Add(new LiteralControl(popup));

            popup = @"</div></div></div><div class=""popupMenuBottom""><div class=""popupMenuBottomBg"">&nbsp;</div>"
                    +
                    @"<div class=""popupMenuBottomLeftCorner"">&nbsp;</div><div class=""popupMenuBottomRightCorner"">&nbsp;</div>"
                    + @"</div></div>";
            Controls.Add(new LiteralControl(popup));
            ViewState["AvailableGroups"] = GroupsToIDs(_availableGroups);
            ViewState["InheritedGroups"] = GroupsToIDs(_inheritedGroups);
            ViewState["SelectedGroups"] = GroupsToIDs(_selectedGroups);
            ViewState["DeselectedGroups"] = GroupsToIDs(_deselectedGroups);
        }
        
        private string GroupsToIDs(IEnumerable<UserGroup> groups)
        {
            string ids = string.Empty;
            foreach (UserGroup g in groups)
            {
                if (ids != string.Empty)
                    ids += ",";
                ids += g.ID;
            }
            return ids;
        }
        
        private IList<UserGroup> IDsToGroups(string ids)
        {
            IList<UserGroup> groups = new List<UserGroup>();
            if (string.IsNullOrEmpty(ids))
                return groups;
            IUserRepository userRepository = new UserRepository();
            foreach (string id in ids.Split(",".ToCharArray()))
                groups.Add(userRepository.GetUserGroup(int.Parse(id)));
            return groups;
        }
    }
}